//! 枚举示例
//!
//! 枚举允许你通过列举所有可能的值来定义一个类型

/// 基础枚举示例
///
/// 定义一个表示方向的枚举
///
/// 基础 C 风格枚举
#[allow(dead_code)]
enum Direction {
    North,
    South,
    East,
    West,
}

/// 使用枚举值
pub fn basic_enum() {
    let direction = Direction::North;

    match direction {
        Direction::North => println!("向北"),
        Direction::South => println!("向南"),
        Direction::East => println!("向东"),
        Direction::West => println!("向西"),
    }

    // 隐式赋值：默认从 0 开始递增
    assert_eq!(Direction::North as i32, 0);
    assert_eq!(Direction::South as i32, 1);
}

/// 显式指定值的枚举
///
/// 显式赋值：可指定任意整数值
#[allow(dead_code)]
enum HttpStatus {
    Ok = 200,
    Created = 201,
    BadRequest = 400,
    Unauthorized = 401,
    Forbidden = 403,
    NotFound = 404,
}

pub fn enum_with_explicit_values() {
    // 显式赋值：可指定任意整数值
    assert_eq!(HttpStatus::Ok as i32, 200);

    println!("HTTP状态码:");
    println!("Ok: {}", HttpStatus::Ok as i32);
    println!("Created: {}", HttpStatus::Created as i32);
    println!("BadRequest: {}", HttpStatus::BadRequest as i32);
}

/// 内存表示示例
///
/// 内存表示：默认使用最小能容纳值的整数类型
/// 在 Rust 中，枚举的内存表示（即枚举值在内存中如何存储）是一个重要的优化点。
/// 对于类C风格的枚举（即不带数据的枚举），Rust编译器会选择一个合适的整数类型来存储枚举值，
/// 这个类型的大小（占用的字节数）是能够容纳枚举中所有变体的最小整数类型
/// 例如，如果枚举的变体值在0到255之间，编译器可能会选择`u8`（1字节）
#[repr(u8)] // 显式指定内存表示
#[allow(dead_code)]
enum Permissions {
    Read = 1,
    Write = 2,
    Execute = 4,
}

/// 默认布局示例
///
/// 默认布局：可能重排字段优化空间
/// 实际大小可能小于 C 布局
#[repr(C)] // C 交互,强制 C 兼容布局
#[allow(dead_code)]
enum CErrorCode {
    NoError = 0,
    IOError = -1,
    InvalidData = -2,
}

/// 带数据的枚举示例
///
/// 枚举的每个变体可以包含不同类型和数量的数据
///
/// 携带数据的变体
#[allow(dead_code)]
enum WebEvent {
    PageLoad,                 // 无数据
    KeyPress(char),           // 单个字符
    Paste(String),            // String类型
    Click { x: i64, y: i64 }, // 匿名结构体
}

/// 为枚举实现方法
impl WebEvent {
    fn handle_event(&self) {
        // 模式匹配
        match self {
            WebEvent::PageLoad => println!("Page loaded"),
            WebEvent::KeyPress(c) => println!("Pressed key: {c}"),
            WebEvent::Click { x, y } => println!("Clicked at ({x}, {y})"),
            WebEvent::Paste(s) => println!("Pasted text: {s}"),
        }
    }
}

/// 使用带数据的枚举
pub fn enum_with_data() {
    let msg1 = Message::Quit;
    let msg2 = Message::Move { x: 10, y: 20 };
    let msg3 = Message::Write(String::from("hello"));
    let msg4 = Message::ChangeColor(255, 0, 0);

    // 使用 match 处理枚举
    fn process_message(msg: Message) {
        match msg {
            Message::Quit => println!("退出消息"),
            Message::Move { x, y } => println!("移动到坐标 ({x}, {y})"),
            Message::Write(text) => println!("写入文本: {text}"),
            Message::ChangeColor(r, g, b) => println!("改变颜色为 RGB({r}, {g}, {b})"),
        }
    }

    process_message(msg1);
    process_message(msg2);
    process_message(msg3);
    process_message(msg4);

    // 处理WebEvent枚举
    let event1 = WebEvent::PageLoad;
    let event2 = WebEvent::KeyPress('c');
    let event3 = WebEvent::Paste("Hello, world!".to_string());
    let event4 = WebEvent::Click { x: 100, y: 200 };

    event1.handle_event();
    event2.handle_event();
    event3.handle_event();
    event4.handle_event();
}

/// 带数据的枚举示例
///
/// 枚举的每个变体可以包含不同类型和数量的数据
#[allow(dead_code)]
enum Message {
    Quit,                       // 没有关联数据的变体
    Move { x: i32, y: i32 },    // 包含匿名结构体的变体
    Write(String),              // 包含单个String的变体
    ChangeColor(i32, i32, i32), // 包含三个i32的变体
}

/// Option枚举示例
///
/// Option 是 Rust 标准库中的一个枚举，用于表示一个值可能存在（Some）或不存在（None）
pub fn option_enum() {
    // Option 枚举定义如下：
    // enum Option<T> {
    //     Some(T),
    //     None,
    // }

    let some_number = Some(5);
    let some_string = Some("a string");
    let absent_number: Option<i32> = None;

    println!("Option示例:");
    println!("some_number: {some_number:?}");
    println!("some_string: {some_string:?}");
    println!("absent_number: {absent_number:?}");

    // 使用 match 处理 Option 值
    match some_number {
        Some(n) => println!("数字是: {n}"),
        None => println!("没有数字"),
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_basic_enum() {
        basic_enum();
    }

    #[test]
    fn test_enum_with_explicit_values() {
        enum_with_explicit_values();
    }

    #[test]
    fn test_enum_with_data() {
        enum_with_data();
    }

    #[test]
    fn test_option_enum() {
        option_enum();
    }
}
